package com.mokairui.share_model_nolock;

import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;
import java.util.function.Consumer;
import java.util.function.Supplier;

/**
 * @Description 累加器
 *         对比原子的递增效率更高, 原因: 性能提升的原因很简单, 就是在有竞争的时, 设置多个累加单元, Thread-0 累加 Cell[0],
 *         而 Thread-1 累加 Cell[1]... 最后将结果汇总. 这样他们在累加时操作的不同的Cell变量, 因此减少了CAS重试失败, 从而
 *         提高性能.
 * @Author Mokairui
 * @Since 2021/10/5
 */
@Slf4j(topic = "c.LongAdder")
public class LongAdderDemo {

    public static void main(String[] args) {
        demo(AtomicLong::new, AtomicLong::getAndIncrement);
        // 使用累加器, 明显效率更高
        demo(LongAdder::new, LongAdder::increment);
    }

    private static <T> void demo(Supplier<T> adderSupplier, Consumer<T> action) {
        T adder = adderSupplier.get();
        long start = System.nanoTime();
        List<Thread> ts = new ArrayList<>();

        // 4个线程, 每个人累加50万
        for (int i = 0; i < 40; i++) {
            ts.add(new Thread(() -> {
                for (int j = 0; j < 500000; j++) {
                    action.accept(adder);
                }
            }));
        }

        ts.forEach(Thread::start);
        ts.forEach(it -> {
            try {
                it.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        long end = System.nanoTime();
        System.out.println(String.format("%s cost: %s", adder, (end - start) / 1000_000));
    }
}
